// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package os

const (
	PathSeparator     = '\\' // OS特定路径分隔符
	PathListSeparator = ';'  // OS特定路径列表分隔符
)

// IsPathSeparator报告c是否为目录分隔符字符。
func IsPathSeparator(c uint8) bool {
	// 注意：Windows接受/作为路径分隔符。
	return c == '\\' || c == '/'
}

// basename从路径名中删除后面的斜杠和前面的
// 目录名和驱动器号。
func basename(name string) string {
	// 删除驱动器号
	if len(name) == 2 && name[1] == ':' {
		name = "."
	} else if len(name) > 2 && name[1] == ':' {
		name = name[2:]
	}
	i := len(name) - 1
	// 删除尾随斜杠
	for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
		name = name[:i]
	}
	// 删除前导目录名
	for i--; i >= 0; i-- {
		if name[i] == '/' || name[i] == '\\' {
			name = name[i+1:]
			break
		}
	}
	return name
}

func isAbs(path string) (b bool) {
	v := volumeName(path)
	if v == "" {
		return false
	}
	path = path[len(v):]
	if path == "" {
		return false
	}
	return IsPathSeparator(path[0])
}

func volumeName(path string) (v string) {
	if len(path) < 2 {
		return ""
	}
	// 带有驱动器号
	c := path[0]
	if path[1] == ':' &&
		('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
			'A' <= c && c <= 'Z') {
		return path[:2]
	}
	// 是否为UNC 
	if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
		!IsPathSeparator(path[2]) && path[2] != '.' {
		// 首先是前导“\\”，然后不应该是“\\”。它的服务器名。
		for n := 3; n < l-1; n++ {
			// 第二，下一个“\”不应重复。
			if IsPathSeparator(path[n]) {
				n++
				// 第三个，后面跟一些字符。它的共享名。
				if !IsPathSeparator(path[n]) {
					if path[n] == '.' {
						break
					}
					for ; n < l; n++ {
						if IsPathSeparator(path[n]) {
							break
						}
					}
					return path[:n]
				}
				break
			}
		}
	}
	return ""
}

func fromSlash(path string) string {
	// 如果存在，则将每个“/”替换为“\\”
	var pathbuf []byte
	var lastSlash int
	for i, b := range path {
		if b == '/' {
			if pathbuf == nil {
				pathbuf = make([]byte, len(path))
			}
			copy(pathbuf[lastSlash:], path[lastSlash:i])
			pathbuf[i] = '\\'
			lastSlash = i + 1
		}
	}
	if pathbuf == nil {
		return path
	}

	copy(pathbuf[lastSlash:], path[lastSlash:])
	return string(pathbuf)
}

func dirname(path string) string {
	vol := volumeName(path)
	i := len(path) - 1
	for i >= len(vol) && !IsPathSeparator(path[i]) {
		i--
	}
	dir := path[len(vol) : i+1]
	last := len(dir) - 1
	if last > 0 && IsPathSeparator(dir[last]) {
		dir = dir[:last]
	}
	if dir == "" {
		dir = "."
	}
	return vol + dir
}

// 这是通过runtime.canUseLongPath上的go:linkname设置的，当操作系统
// 支持选择正确的长路径处理而无需修复时，此设置为真。
var canUseLongPaths bool

// fixLongPath在需要时返回
// 路径的扩展长度（\\？\-前缀）形式，以避免Windows强加的默认260字符文件
// 路径限制。如果路径不容易转换为扩展长度形式（例如，如果路径是相对路径
// 或包含..元素），或者足够短，则fixLongPath返回未修改的
// 路径。
// 参见https:
func fixLongPath(path string) string {
	if canUseLongPaths {
		return path
	}
	// 如果路径“短”，则不执行任何操作（也不分配）。
	// 根据经验（至少在Windows Server 2013 builder上），
	// 内核可以任意使用<248字节。该
	// 与上述文档所述内容相匹配：
	// “在使用API创建目录时，指定的
	// 路径不能太长，以至于您无法附加8.3文件
	// 名称（即，目录名称不能超过MAX_path 
	// 减去12）。”因为最大路径是260，260-12=248。
	// 
	// MSDN文档似乎表示248字节长的正常路径
	// 可以工作；根据经验，路径长度必须小于248字节。
	if len(path) < 248 {
		// 不要修复。（这是Go 1.7及更早版本的工作原理，
		// 不自动生成\\？\form）
		return path
	}

	// 扩展表单以\\？\、开头，如
	// /\？\c:\windows\foo.txt或\\？\UNC\server\share\foo.txt。
	// 扩展表单禁用对的求值。和路径
	// 元素，并禁用对/的解释为等效
	// to\。此处的转换重写/到\并省略
	// 。元素以及尾部或重复分隔符。对于
	// 简单性，它完全避免了相对
	// 路径或包含..的路径的转换。。元素。目前，
	// /\\\server\share路径未转换为
	// /\？\UNC\server\share路径，因为执行此操作的规则
	// 没有很好地指定。
	if len(path) >= 2 && path[:2] == `\\` {
		// 不要规范化UNC路径。
		return path
	}
	if !isAbs(path) {
		// 相对路径
		return path
	}

	const prefix = `\\?`

	pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
	copy(pathbuf, prefix)
	n := len(path)
	r, w := 0, len(prefix)
	for r < n {
		switch {
		case IsPathSeparator(path[r]):
			// 空块
			r++
		case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
			// ./
			r++
		case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
			// ../当前未处理
			return path
		default:
			pathbuf[w] = '\\'
			w++
			for ; r < n && !IsPathSeparator(path[r]); r++ {
				pathbuf[w] = path[r]
				w++
			}
		}
	}
	// 驱动器的根目录需要一个尾部\
	if w == len(`\\?\c:`) {
		pathbuf[w] = '\\'
		w++
	}
	return string(pathbuf[:w])
}

// fixRootDirectory修复对驱动器根目录的引用
// 具有所需的尾部斜线
func fixRootDirectory(p string) string {
	if len(p) == len(`\\?\c:`) {
		if IsPathSeparator(p[0]) && IsPathSeparator(p[1]) && p[2] == '?' && IsPathSeparator(p[3]) && p[5] == ':' {
			return p + `\`
		}
	}
	return p
}
